import logging
import os
import json
import string
import subprocess
import shlex
import random
import time
import shutil
from threading import Timer
from typing import Dict
import ssl
from pymisp import ExpandedPyMISP


LOGGER_NAME = 'androidsandbox'


class Utils:
    @staticmethod
    def load_config() -> Dict:
        """Load configurations."""
        __location__ = os.path.realpath(
            os.path.join(os.getcwd(), os.path.dirname(__file__)))
        with open(os.path.join(__location__, 'config.json')) as f:
            config = json.load(f)
        return config

    @staticmethod
    def setup_logger(logger_path, logger_level):
        result = logging.getLogger(LOGGER_NAME)
        result.setLevel(logging.DEBUG)
        fmt = logging.Formatter('%(asctime)s - %(process)d - %(threadName)s '
                                '- %(filename)s - %(levelname)s - %(message)s',
                                datefmt='%Y-%m-%d %H:%M:%S')
        # level = 'DEBUG'
        # __location__ = os.path.realpath(
        #     os.path.join(os.getcwd(), os.path.dirname(__file__)))
        # with open(os.path.join(__location__, 'config.json')) as f:
        #     logger_path = json.load(f)['logger_path']
        f_handler = logging.FileHandler(logger_path)
        f_handler.setLevel(logger_level)
        f_handler.setFormatter(fmt)
        # console = logging.StreamHandler()
        # console.setLevel(level)
        # console.setFormatter(fmt)
        result.addHandler(f_handler)
        # result.addHandler(console)
        return result

    @staticmethod
    def run_cmd(cmd, timeout=15, shell=False):
        outs, errs = None, None
        proc = subprocess.Popen(shlex.split(cmd),
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE,
                                universal_newlines=True,
                                shell=shell)
        timer = Timer(timeout, lambda process: process.kill(), [proc])
        try:
            timer.start()
            outs, errs = proc.communicate()
            return outs, errs
        finally:
            timer.cancel()

    @staticmethod
    def get_random_alphanumeric_string(length):
        letters_and_digits = string.ascii_letters + string.digits
        result_str = ''.join(
            (random.choice(letters_and_digits) for i in range(length)))
        return result_str

    @staticmethod
    def wait_until(condition_func, timeout: int) -> bool:
        """
         Return True if the condition function hit true.
        :param condition_func:
        :param timeout: second
        :return:
        """
        deadline = time.time() + timeout
        while time.time() < deadline:
            if condition_func():
                return True
            else:
                time.sleep(1)
        return False

    @staticmethod
    def gen_id():
        # Generate growing id
        my_id = 0
        while True:
            my_id += 1
            yield my_id

    @staticmethod
    def init_misp(url, key):
        ssl._create_default_https_context = ssl._create_unverified_context
        return ExpandedPyMISP(url, key, ssl=False)

    @staticmethod
    def remove_path(path):
        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)


CFG = Utils.load_config()


if not logging.root.manager.loggerDict.get(LOGGER_NAME, False):
    logger = Utils.setup_logger(CFG['logger_path'], CFG['logger_level'])
else:
    logger = logging.getLogger(LOGGER_NAME)